package cn.getech.data.development.service.impl;

import cn.getech.data.development.constant.ModelTypeEnum;
import cn.getech.data.development.entity.BdpDataAssetsModel;
import cn.getech.data.development.entity.JobNodeConf;
import cn.getech.data.development.entity.TableFieldInfo;
import cn.getech.data.development.entity.TableInfo;
import cn.getech.data.development.mapper.BdpDataAssetsModelMapper;
import cn.getech.data.development.mapper.JobNodeConfMapper;
import cn.getech.data.development.mapper.TableFieldInfoMapper;
import cn.getech.data.development.model.OutputDbInfoDto;
import cn.getech.data.development.model.ResultDto;
import cn.getech.data.development.model.dto.AlgorithmDevelopmentRerunBigDataDto;
import cn.getech.data.development.model.dto.InputDbInfoDto;
import cn.getech.data.development.service.IDataAssetsModelService;
import cn.getech.data.development.service.TableFieldInfoService;
import cn.getech.data.intelligence.common.exception.RRException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 * 模型实时状态表 服务实现类
 * </p>
 *
 * @author zzm
 * @since 2021-01-19
 */
@Service
public class BdpDataAssetsModelServiceImpl extends ServiceImpl<BdpDataAssetsModelMapper, BdpDataAssetsModel> implements IDataAssetsModelService {
    @Autowired
    BdpDataAssetsModelMapper dataAssetsModelMapper;
    @Autowired
    TableFieldInfoService tableFieldInfoService;
    @Autowired
    JobNodeConfMapper jobNodeConfMapper;
    @Autowired
    TableFieldInfoMapper tableFieldInfoMapper;
//    @Autowired
//    BdpModelTaskMapper bdpModelTaskMapper;

    /**
     * 通过算法类型和模型类型查询最进成功的模型
     * @param param
     * @return
     */
    @Override
    public List<BdpDataAssetsModel> selectModelsByAlgorithmTypeAndModelType(Map<String, String> param) {
        List<BdpDataAssetsModel> dataAssetsModels = dataAssetsModelMapper.selectModelsByAlgorithmTypeAndModelType(param);
        return dataAssetsModels;
    }

    /**
     * 判断预测的hive表是否包含x字段和主键字段
     * @param tableInfoList
     * @param modelId
     * @return
     */
    @Override
    public List<TableInfo> pdTableExistsXfieldAndPrimaryKey(List<TableInfo> tableInfoList, Integer modelId) {
        //根据模型id,查询出构建x和主键的字段;
        BdpDataAssetsModel dataAssetsModel = dataAssetsModelMapper.selectOne(new QueryWrapper<BdpDataAssetsModel>().eq("id",modelId).isNotNull("last_build_detail"));
        if(null == dataAssetsModel){
            throw new RRException("该模型未构建成功");
        }
        String lastBuildDetail = dataAssetsModel.getLastBuildDetail();
        JSONObject jsonObject = JSON.parseObject(lastBuildDetail);
        JSONArray xField = jsonObject.getJSONArray("inputs");
        String primaryKey = (String)jsonObject.get("primary_key");
        List<String> xFields = JSON.parseObject(xField.toJSONString(), new TypeReference<List<String>>() {});
        xFields.add(primaryKey);

        if(CollectionUtils.isNotEmpty(tableInfoList)){
            Iterator<TableInfo> iterator = tableInfoList.iterator();
            while(iterator.hasNext()){
                List<TableFieldInfo> tableFieldInfos = tableFieldInfoService.list(new QueryWrapper<TableFieldInfo>().eq("table_id", iterator.next().getId()));
                int count = 0;
                for(String field : xFields){
                    for(TableFieldInfo tableFieldInfo : tableFieldInfos){
                        if(tableFieldInfo.getFieldName().equals(field)){
                            count++;
                            break;
                        }
                    }
                }
                if(count != xFields.size()){
                    iterator.remove();
                }
            }
        }
        return tableInfoList;
    }

    /**
     *返回映射结果集
     * @param modelTypeId
     * @param modelId
     * @param outputPreTableId
     * @return
     */
    @Override
    public List<Map<String, Object>> selectReultFieldMapperList(String modelTypeId,Integer modelId,Integer outputPreTableId) {
        BdpDataAssetsModel dataAssetsModel = dataAssetsModelMapper.selectOne(new QueryWrapper<BdpDataAssetsModel>().eq("id",modelId).isNotNull("last_build_detail"));
        if(null == dataAssetsModel){
            throw new RRException("该模型未构建成功");
        }
        List<TableFieldInfo> tableFieldInfos = tableFieldInfoMapper.selectList(new QueryWrapper<TableFieldInfo>().select("id","field_name","primary_key","field_type").eq("table_id", outputPreTableId));
        String lastBuildDetail = dataAssetsModel.getLastBuildDetail();
        JSONObject jsonObject = JSON.parseObject(lastBuildDetail);
        JSONArray yField = jsonObject.getJSONArray("outputs");
        String primaryKey = (String)jsonObject.get("primary_key");
        List<String> yFields = JSON.parseObject(yField.toJSONString(), new TypeReference<List<String>>() {
        });
        yFields.add(0,primaryKey);
        //获取主键和y字段的个数;
        Integer count = yFields.size();
        if(count != tableFieldInfos.size()){
            return null;
        }
        //过滤数据类型不一致的表;
        List<String> fileterTableType = new LinkedList<>();
        if(!yFields.contains("predY")){
            for(String field : yFields){
                String fieldType = getTableFiledId(dataAssetsModel.getTabelId(), field).getFieldType();
                fileterTableType.add(fieldType);
            }
            //判断预测表的类型预测结果字段类型是否一致
            boolean flag = checkTableFieldType(tableFieldInfos, fileterTableType);
            if(!flag){
                return null;
            }
        }
        List<Map<String,Object>> dataList= new LinkedList<>();
        //如果是聚类模型,则需要拼接predY字段;
        if(ModelTypeEnum.CLUSTERING.getCode().equals(modelTypeId)){
            Map<String,Object> idMap = new HashMap<>();
            idMap.put("filedName",primaryKey);
            idMap.put("fieldId",getTableFiledId(dataAssetsModel.getTabelId(),primaryKey).getId());
            idMap.put("filedValue",filterTableInfoField(tableFieldInfos,getTableFiledId(dataAssetsModel.getTabelId(),primaryKey).getFieldType()));
            idMap.put("fieldType",getTableFiledId(dataAssetsModel.getTabelId(),primaryKey).getFieldType());
            idMap.put("outputPreCheckedId","");
            idMap.put("outputPreCheckedName","");
            dataList.add(idMap);
            Map<String,Object> predMap = new HashMap<>();
            predMap.put("filedName","predY");
            predMap.put("fieldId",0);
            predMap.put("filedValue",tableFieldInfos);
            predMap.put("fieldType","");
            predMap.put("outputPreCheckedId","");
            predMap.put("outputPreCheckedName","");
            dataList.add(predMap);
            return dataList;
        }
        //页面展示显示对应的数据类型;
        for(String field : yFields){
            Map<String,Object> filedMap = new HashMap<>();
            filedMap.put("filedName",field);
            filedMap.put("fieldId",getTableFiledId(dataAssetsModel.getTabelId(),field).getId());
            filedMap.put("filedValue",filterTableInfoField(tableFieldInfos,getTableFiledId(dataAssetsModel.getTabelId(),field).getFieldType()));
            filedMap.put("fieldType",getTableFiledId(dataAssetsModel.getTabelId(),field).getFieldType());
            filedMap.put("outputPreCheckedId","");
            filedMap.put("outputPreCheckedName","");
            dataList.add(filedMap);
        }
        return dataList;
    }

    /**
     * 返回算法开发任务给大数据;
     * @param jobNodeId
     * @return
     */
    @Override
    public AlgorithmDevelopmentRerunBigDataDto returnAlgorithmDevDataToBigData(Integer jobNodeId,Integer modelId) {
        AlgorithmDevelopmentRerunBigDataDto algorithmDevelopmentRerunBigDataDto = new AlgorithmDevelopmentRerunBigDataDto();
        algorithmDevelopmentRerunBigDataDto.setOperation("appModel");
        List<JobNodeConf> jobNodeConfs = jobNodeConfMapper.selectList(new QueryWrapper<JobNodeConf>().eq("job_node_id", jobNodeId));
        //输入参数
        InputDbInfoDto inputDbInfoDto = new InputDbInfoDto();
        inputDbInfoDto.setDbType("");
        inputDbInfoDto.setUrl("");
        inputDbInfoDto.setUser("");
        inputDbInfoDto.setPassword("");
        //输出参数;
        OutputDbInfoDto outputDbInfoDto = new OutputDbInfoDto();
        outputDbInfoDto.setDbType("");
        outputDbInfoDto.setUrl("");
        outputDbInfoDto.setUser("");
        outputDbInfoDto.setPassword("");
        //输出参数中映射result
        ResultDto resultDto = new ResultDto();
        if(null!=jobNodeConfs && !jobNodeConfs.isEmpty()){
            for(JobNodeConf jobNodeConf : jobNodeConfs){
                if(jobNodeConf.getKey().equals("modelTypeId")){
                    algorithmDevelopmentRerunBigDataDto.setModelType(jobNodeConf.getValue());
                }
                if(jobNodeConf.getKey().equals("classificationType")){
                    algorithmDevelopmentRerunBigDataDto.setClassificationType(jobNodeConf.getValue());
                }
                if(jobNodeConf.getKey().equals("algorithmTypeName")){
                    algorithmDevelopmentRerunBigDataDto.setAlgorithmType(jobNodeConf.getValue());
                }

                if(jobNodeConf.getKey().equals("inputPreDbName")){
                    inputDbInfoDto.setDbName(jobNodeConf.getValue());
                }
                if(jobNodeConf.getKey().equals("inputPreTableName")){
                    inputDbInfoDto.setTableName(jobNodeConf.getValue());
                }
                if(jobNodeConf.getKey().equals("outputPreDbName")){
                   outputDbInfoDto.setDbName(jobNodeConf.getValue());
                }
                if(jobNodeConf.getKey().equals("outputPreTableName")){
                    outputDbInfoDto.setTableName(jobNodeConf.getValue());
                }
                if(jobNodeConf.getKey().equals("preResultInfos")){
                    List<Map<String, Object>> preResultInfosList = JSON.parseObject(jobNodeConf.getValue(), new TypeReference<List<Map<String, Object>>>() {});
                    preResultInfosList.sort(Comparator.comparing(m -> (Integer)m.get("outputPreCheckedId")));
                    List<String> inputCols = new LinkedList<>();
                    List<String> outputCols = new LinkedList<>();
                    for(Map<String,Object> objectMap : preResultInfosList){
                       inputCols.add((String)objectMap.get("filedName"));
                       outputCols.add((String)objectMap.get("outputPreCheckedName"));
                    }
                    resultDto.setOutputCols(outputCols);
                    resultDto.setInputCols(inputCols);
                }
            }
        }
        BdpDataAssetsModel dataAssetsModel = dataAssetsModelMapper.selectById(modelId);
        String successModelParam = "";
        String primaryKey = "";
        String modelPath = "";
        if(null != dataAssetsModel){
             successModelParam = dataAssetsModel.getLastBuildDetail();
             JSONObject jsonObject = JSONObject.parseObject(successModelParam);
             primaryKey = (String)jsonObject.get("primary_key");
             modelPath  = (String)jsonObject.get("model_address");
             algorithmDevelopmentRerunBigDataDto.setModelPath(modelPath);
             JSONArray xField = jsonObject.getJSONArray("inputs");
             List<String> xFields = JSON.parseObject(xField.toJSONString(), new TypeReference<List<String>>() {});
             JSONArray yField = jsonObject.getJSONArray("outputs");
             List<String> yFields = JSON.parseObject(yField.toJSONString(), new TypeReference<List<String>>() {});;
             inputDbInfoDto.setPrimaryKey(primaryKey);
             inputDbInfoDto.setXCols(xFields);
             inputDbInfoDto.setYCols(yFields);
             outputDbInfoDto.setResult(resultDto);


        }
        algorithmDevelopmentRerunBigDataDto.setInputDbInfo(inputDbInfoDto);
        algorithmDevelopmentRerunBigDataDto.setOutputDbInfo(outputDbInfoDto);
        return algorithmDevelopmentRerunBigDataDto;
    }



    /**
     * 检验是否存在主键
     * @param tableId
     * @param fieldName
     * @return
     */
    @Override
    public void checkIsPrimaryKey(Integer tableId, String fieldName) {
        TableFieldInfo tableFieldInfo = tableFieldInfoService.getOne(new QueryWrapper<TableFieldInfo>().eq("table_id", tableId).eq("field_name", fieldName));
        if(null != tableFieldInfo){
            //判断是否为主键
            if(tableFieldInfo.getPrimaryKey() != 1){
                throw new RRException("当前选择的预测输出表字段不是主键");
            }
        }
    }

    /**
     *检验是否有相同的字段
     * @param mapList
     * @return
     */
    @Override
    public void checkSameFiled(List<Map<String, Object>> mapList) {
        List<Object> pdList = new LinkedList<>();
        for(Map<String,Object> map : mapList){
            pdList.add(map.get("outputPreCheckedName"));
        }
        long count = pdList.stream().distinct().count();
        if(count != pdList.size()){
            throw new RRException("请选择不同的预测输出表字段");
        }
    }

    @Override
    public boolean checkMapperResultFiledType(Integer modelId,List<Map<String,String>>preResultInfos) {
        BdpDataAssetsModel dataAssetsModel = dataAssetsModelMapper.selectOne(new QueryWrapper<BdpDataAssetsModel>().eq("id", modelId).isNotNull("last_build_detail"));
        if(null != dataAssetsModel){

        }
        return false;
    }

    /**
     * 判断预测输出表字段个数是否和映射字段个数相同;
     * @param outputPreTableId
     * @param preResultInfos
     * @return
     */
    @Override
    public void checkMappperResultFiledNum(Integer outputPreTableId, List<Map<String, Object>> preResultInfos) {
        List<TableFieldInfo> tableFieldInfos = tableFieldInfoMapper.selectList(new QueryWrapper<TableFieldInfo>().eq("table_id", outputPreTableId));
        if(null == tableFieldInfos || tableFieldInfos.size()== 0){
            throw  new RRException("该hive字段为空");
        }
        if(null == preResultInfos || preResultInfos.size() == 0){
            throw  new RRException("创建模型的预测字段不存在");
        }
        if(tableFieldInfos.size() != preResultInfos.size()){
            throw  new RRException("预测模型字段和预测输出表字段个数不同");
        }
    }

    public TableFieldInfo getTableFiledId(Integer tableId,String fieldName){
        TableFieldInfo tableFieldInfo = tableFieldInfoMapper.selectOne(new QueryWrapper<TableFieldInfo>().select("id","field_type").eq("table_id", tableId).eq("field_name", fieldName));
        if(null == tableFieldInfo){
            throw new RRException("该字段在表中不存在");
        }
        return tableFieldInfo;
    }

    /**
     * 过滤字段类型不匹配的数据
     * @return
     */
    public List<TableFieldInfo> filterTableInfoField(List<TableFieldInfo> tableFieldInfos,String filedType){
        List<TableFieldInfo> tableFieldInfoList = new LinkedList<>();
        if(null!= tableFieldInfos && tableFieldInfos.size()>0){
            for(TableFieldInfo tableFieldInfo : tableFieldInfos){
                if(tableFieldInfo.getFieldType().equals(filedType)){
                    tableFieldInfoList.add(tableFieldInfo);
                }
            }
        }
        return tableFieldInfoList;

    }

    public boolean checkTableFieldType(List<TableFieldInfo> tableFieldInfos,List<String> fieldTypes){
        int count = 0 ;
        if(CollectionUtils.isNotEmpty(tableFieldInfos) && CollectionUtils.isNotEmpty(fieldTypes)){
            for(TableFieldInfo tableFieldInfo : tableFieldInfos){
                for(String fieldType : fieldTypes){
                    if(tableFieldInfo.getFieldType().equals(fieldType)){
                        count++;
                        break;
                    }
                }
            }
        }
       if(count != fieldTypes.size()){
           return false;
       }
       return true;
    }

}
